﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using VDataAdapter.EventManagement;
using VDataAdapter.BlockingQueue;
using VDataAdapter.TestPreparation;

namespace VDataAdapter
{
 /// <summary>
    /// This class help load data out from file to simulate event
    /// </summary>
    public class TestUtils
    {
        public static Tuple<FirstTimeEvent, Queue<String>> getFirstTimeData()
        {
            return getTestData("\\Event\\GetFirstTime.test");
        }

        public static Tuple<FirstTimeEvent, Queue<String>> getTestData(string path)
        {
            string TEST_DATA = TestDataFolder.GetTestDataFolder();
            PriceServerObjectFile reader = new PriceServerObjectFile();
            Object[] list = reader.ReadFromFile(TEST_DATA + path);

            //TODO: Clean this, at least add type check
            // this is stupid, but debug and read content of the list to know why
            // too sleepy to do it clean now
            FirstTimeEvent e = (FirstTimeEvent)list[2];
            Queue<String> expected = (Queue<string>)list[3];
            return Tuple.Create(e, expected);
        }

        public static Queue<string> ToStringQueue(CommunicationDataQueue queue)
        {
            Queue<string> result = new Queue<string>();
            CommunicationData data;

            while (queue.getQueueSize() > 0)
            {
                data = queue.get();
                result.Enqueue(queue.GetQueueItemString(data));
            }
            return result;
        }

        public static void AssertSameQueue(Queue<string> expected, CommunicationDataQueue actual)
        {
            int minLength = 0;
            
            if (expected.Count >= actual.getQueueSize())
                minLength = actual.getQueueSize();
            else
                minLength = expected.Count;

            Queue<string> actualStrQueue = ToStringQueue(actual);

            for (int i = 0; i < minLength; i++)
            {
                string actualStr = actualStrQueue.Dequeue();
                string expectedStr = expected.Dequeue();

                TimeInVariantAsserter.AreEqual(expectedStr, actualStr, "Item mismatched at index: " + i.ToString());
            }

            Assert.AreEqual(expected.Count, actual.getQueueSize(), "2 queues does not have the same number of elements");
        }



        public static List<T1> CastListObject<T1, T2>(IList<T2> list)
        {
            var result = new List<T1>();
            try
            {
                foreach (T2 item in list)
                {
                    var o = (Object)item;
                    var target = (T1)o;
                    result.Add(target);
                }
            }
            catch (InvalidCastException ex)
            {
                throw new Exception("TestUtils.CastListObject: cannot cast object from : " + typeof(T2).ToString() + " to: " + typeof(T1).ToString() + ex.Message, ex);
            }
            catch (Exception ex)
            {
                throw new Exception("TestUtils.CastListObject: something wrong : " + ex.Message, ex);
            }

            return result;
        }

        /// <summary>
        /// cast list of object T2 to T1     
        /// </summary>
        /// <returns></returns>
        public static T1[] CastListObject<T1, T2>(T2[] list)
        {
            Queue<T1> result = new Queue<T1>();
            Queue<T2> q = ToQueue<T2>(list);
            try
            {
                while (q.Count > 0)
                {
                    Object item = q.Dequeue();
                    T1 target = (T1)item;
                    result.Enqueue(target);
                }
            }
            catch (InvalidCastException ex)
            {
                throw new Exception("TestUtils.CastListObject: cannot cast object from : " + typeof(T2).ToString() + " to: " + typeof(T1).ToString() + ex.Message, ex);
            }
            catch (Exception ex)
            {
                throw new Exception("TestUtils.CastListObject: something wrong : " + ex.Message, ex);
            }

            return result.ToArray();
        }

        public static Queue<T> ToQueue<T>(T[] list)
        {
            var result = new Queue<T>();

            foreach (T e in list)
            {
                result.Enqueue(e);
            }
            return result;
        }

        public static Queue<T1> ToQueueItem1<T1, T2>(Tuple<T1, T2>[] list)
        {
            var result = new Queue<T1>();

            foreach (Tuple<T1,T2> t in list)
            {
                result.Enqueue(t.Item1);
            }
            return result;
        }

        public static Queue<T2> ToQueueItem2<T1, T2>(Tuple<T1, T2>[] list)
        {
            var result = new Queue<T2>();

            foreach (Tuple<T1, T2> t in list)
            {
                result.Enqueue(t.Item2);
            }
            return result;
        }

        public static Queue<T> ToQueue<T>(Queue<Queue<T>> input)
        {
            Queue<T> result = new Queue<T>();

            foreach (Queue<T> q in input)
            {
                foreach(T item in q)
                {
                    result.Enqueue(item);
                }
            }
            return result;
        }
    }
}
